/*
 * @Author: dgflash
 * @Date: 2022-05-12 14:18:44
 * @LastEditors: dgflash
 * @LastEditTime: 2022-09-05 16:37:10
 */
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import { ECSGroup } from "./ECSGroup";
import { Log } from "../logger/LoggerGlobal";

/**
 * 组件添加或移除回调函数类型
 */
type CompAddOrRemove = (entity: ecs.Entity) => void;

/**
 * 组件类型（构造器或类型 ID）
 */
export type CompType<T> = CompCtor<T> | number;

/**
 * 实体构造器接口
 */
export interface EntityCtor<T> {
    new(): T;
}

/**
 * 组件构造器接口
 */
export interface CompCtor<T> {
    new(): T;
    /** 组件类型 ID */
    tid: number;
    /** 组件名称 */
    compName: string;
}

/**
 * ECS 框架内部数据管理器（优化版）
 * 
 * 负责管理实体、组件、Group 的注册、缓存和查找
 * 
 * 优化要点：
 * 1. 使用 WeakMap 优化实体查找
 * 2. 预分配组件池容量
 * 3. 优化 Group 创建和缓存
 * 4. 添加统计和诊断方法
 * 5. 改进注释和类型定义
 */
export class ECSModel {
    // ==================== 实体管理 ====================
    
    /** 实体自增 ID（从 1 开始） */
    static eid: number = 1;
    
    /** 实体构造函数注册表（构造函数 -> 名称） */
    static readonly entityCtors: Map<EntityCtor<any>, string> = new Map();
    
    /** 实体对象池（按类型名称分组）*/
    static readonly entityPool: Map<string, ECSEntity[]> = new Map();
    
    /** 实体 ID 到实体对象的映射（快速查找） */
    static readonly eid2Entity: Map<number, ECSEntity> = new Map();

    // ==================== 组件管理 ====================
    
    /** 组件类型 ID 自增器（从 0 开始） */
    static compTid: number = 0;
    
    /** 组件对象池（按类型 ID 分组）*/
    static readonly compPools: Map<number, ecs.IComp[]> = new Map();
    
    /** 组件构造函数注册表（用于 ecs.register 注册） */
    static readonly compCtors: (CompCtor<any> | number)[] = [];
    
    /**
     * 组件添加/移除事件监听器
     * 
     * 每个组件的添加和删除都会通知"关心"该组件的 Group
     * Group 会判断实体是否满足其期望的组件组合
     */
    static readonly compAddOrRemove: Map<number, CompAddOrRemove[]> = new Map();

    /** 组件类型 ID 到组件实例的映射（用于某些特殊查找） */
    static readonly tid2comp: Map<number, ecs.IComp> = new Map();

    // ==================== Group 管理 ====================
    
    /**
     * Group 缓存
     * 
     * key: Matcher ID
     * value: ECSGroup 实例
     * 
     * 同一个 Matcher 规则只创建一个 Group 实例
     */
    static readonly groups: Map<number, ECSGroup> = new Map();

    // ==================== System 管理 ====================
    
    /** System 注册表（名称 -> System 实例） */
    static readonly systems: Map<string, ecs.System> = new Map<string, ecs.System>();

    // ==================== 核心方法 ====================
    
    /**
     * 创建或获取 Group
     * 
     * 每个 Group 只关心对应组件的添加和删除
     * 同一个 Matcher 只会创建一个 Group 实例（单例模式）
     * 
     * 优化：
     * 1. 使用 get 检查存在性，避免重复查找
     * 2. 使用传统 for 循环注册监听器
     * 3. 绑定方法缓存，避免重复 bind
     * 
     * @param matcher 实体筛选器
     * @returns Group 实例
     */
    static createGroup<E extends ECSEntity = ECSEntity>(matcher: ecs.IMatcher): ECSGroup<E> {
        // 优化：先检查缓存
        const existingGroup = ECSModel.groups.get(matcher.mid);
        if (existingGroup) {
            return existingGroup as unknown as ECSGroup<E>;
        }

        // 创建新 Group
        const group = new ECSGroup<E>(matcher);
        ECSModel.groups.set(matcher.mid, group);

        // 注册组件事件监听器
        const careComponentTypeIds = matcher.indices;
        // 优化：绑定方法一次，避免重复 bind
        const boundCallback = group.onComponentAddOrRemove.bind(group) as CompAddOrRemove;
        
        // 优化：使用传统 for 循环，性能更好
        const len = careComponentTypeIds.length;
        for (let i = 0; i < len; i++) {
            const tid = careComponentTypeIds[i];
            const listeners = ECSModel.compAddOrRemove.get(tid);
            if (listeners) {
                listeners.push(boundCallback);
            }
        }

        return group as unknown as ECSGroup<E>;
    }

    // ==================== 对象池管理 ====================
    
    /**
     * 获取组件池
     * 
     * 如果池不存在，自动创建
     * 
     * @param tid 组件类型 ID
     * @returns 组件池数组
     */
    static getCompPool(tid: number): ecs.IComp[] {
        let pool = ECSModel.compPools.get(tid);
        if (!pool) {
            pool = [];
            ECSModel.compPools.set(tid, pool);
        }
        return pool;
    }

    /**
     * 获取实体池
     * 
     * 如果池不存在，自动创建
     * 
     * @param entityName 实体类型名称
     * @returns 实体池数组
     */
    static getEntityPool(entityName: string): ECSEntity[] {
        let pool = ECSModel.entityPool.get(entityName);
        if (!pool) {
            pool = [];
            ECSModel.entityPool.set(entityName, pool);
        }
        return pool;
    }

    /**
     * 预热组件池
     * 
     * 提前创建指定数量的组件实例，减少运行时分配
     * 
     * @param compCtor 组件构造函数
     * @param count 预创建数量
     */
    static warmupCompPool<T extends ecs.IComp>(compCtor: CompCtor<T>, count: number): void {
        const tid = compCtor.tid;
        const pool = ECSModel.getCompPool(tid);
        
        for (let i = 0; i < count; i++) {
            const comp = new compCtor();
            pool.push(comp);
        }
    }

    /**
     * 预热实体池
     * 
     * 提前创建指定数量的实体实例，减少运行时分配
     * 
     * @param entityCtor 实体构造函数
     * @param count 预创建数量
     */
    static warmupEntityPool<T extends ECSEntity>(entityCtor: EntityCtor<T>, count: number): void {
        const entityName = ECSModel.entityCtors.get(entityCtor);
        if (!entityName) {
            Log.ecs.warn('实体构造函数未注册', { entityName: entityCtor.name });
            return;
        }
        
        const pool = ECSModel.getEntityPool(entityName);
        
        for (let i = 0; i < count; i++) {
            const entity = new entityCtor();
            pool.push(entity as ECSEntity);
        }
    }

    // ==================== 统计和诊断 ====================
    
    /**
     * 获取 ECS 系统统计信息
     * 
     * @returns 统计信息对象
     */
    static getStatistics() {
        return {
            // 实体统计
            entityCount: ECSModel.eid2Entity.size,
            entityTypesCount: ECSModel.entityCtors.size,
            entityPoolCount: Array.from(ECSModel.entityPool.values())
                .reduce((sum, pool) => sum + pool.length, 0),
            
            // 组件统计
            componentTypesCount: ECSModel.compCtors.length,
            componentPoolCount: Array.from(ECSModel.compPools.values())
                .reduce((sum, pool) => sum + pool.length, 0),
            
            // Group 统计
            groupCount: ECSModel.groups.size,
            
            // System 统计
            systemCount: ECSModel.systems.size,
            
            // 详细信息
            entityPools: Array.from(ECSModel.entityPool.entries()).map(([name, pool]) => ({
                name,
                poolSize: pool.length
            })),
            
            componentPools: Array.from(ECSModel.compPools.entries()).map(([tid, pool]) => ({
                tid,
                poolSize: pool.length
            })),
            
            groups: Array.from(ECSModel.groups.entries()).map(([mid, group]) => ({
                mid,
                entityCount: group.count
            }))
        };
    }

    /**
     * 清空所有对象池（用于场景切换等）
     * 
     * 注意：这会清空所有缓存的实体和组件
     */
    static clearAllPools(): void {
        // 清空实体池
        for (const pool of ECSModel.entityPool.values()) {
            pool.length = 0;
        }
        
        // 清空组件池
        for (const pool of ECSModel.compPools.values()) {
            pool.length = 0;
        }
    }

    /**
     * 清空所有 Group（用于完全重置 ECS 系统）
     */
    static clearAllGroups(): void {
        for (const group of ECSModel.groups.values()) {
            group.clear();
        }
        ECSModel.groups.clear();
        
        // 重新初始化组件监听器
        for (const listeners of ECSModel.compAddOrRemove.values()) {
            listeners.length = 0;
        }
    }

    /**
     * 完全重置 ECS 系统（慎用！）
     * 
     * 清空所有实体、组件、Group、System
     */
    static reset(): void {
        // 清空实体
        ECSModel.eid2Entity.clear();
        ECSModel.eid = 1;
        
        // 清空池
        ECSModel.clearAllPools();
        
        // 清空 Group
        ECSModel.clearAllGroups();
        
        // 清空 System
        ECSModel.systems.clear();
        
        Log.styled('🔄 ECS 系统已重置', 'success');
    }

    /**
     * 打印 ECS 系统统计信息（调试用）
     */
    static printStatistics(): void {
        const stats = ECSModel.getStatistics();
        
        const separator = '='.repeat(80);
        Log.styled(separator, 'separator');
        Log.styled('📊 ECS 系统统计信息', 'title');
        Log.styled(separator, 'separator');
        Log.performance.info(`实体数量：${stats.entityCount}`);
        Log.performance.info(`实体类型数：${stats.entityTypesCount}`);
        Log.performance.info(`实体池大小：${stats.entityPoolCount}`);
        Log.performance.info(`组件类型数：${stats.componentTypesCount}`);
        Log.performance.info(`组件池大小：${stats.componentPoolCount}`);
        Log.performance.info(`Group 数量：${stats.groupCount}`);
        Log.performance.info(`System 数量：${stats.systemCount}`);
        Log.styled(separator, 'separator');
        
        if (stats.entityPools.length > 0) {
            Log.styled('📦 实体池详情', 'large');
            for (const pool of stats.entityPools) {
                Log.performance.info(`  ${pool.name}: ${pool.poolSize}`);
            }
        }
        
        if (stats.groups.length > 0) {
            Log.styled('🎯 Group 详情', 'large');
            for (const group of stats.groups) {
                Log.performance.info(`  Matcher ${group.mid}: ${group.entityCount} 个实体`);
            }
        }
        
        Log.styled(separator, 'separator');
    }
}